#!/usr/bin/python
#-*- coding: utf-8 -*-
from OpenGL.GL import *
from OpenGL.arrays import vbo
from numpy import array
import Image

from GameConfigFile import *
from vbo_handler import VBOHandler

# INFO:
# skybox mit TEXTURE_CUBE_MAP  texturen zeichnen ok, 3. koordinate ist die Achse x,y,z ist einfach die selbe wie von der textur

# TODO:
# obj datei schreiben
# obj einlesen und vbo zeichnen

class Skybox(object):
    """Skybox mit GL_CUBE_MAP realisiert"""
    def __init__(self, file_obj=None):
                    
        self.vbo_handler = None
        self.__SIZE_VERTEX_COORDINATES = None
        
        if file_obj==None:
            self.vbo_handler = VBOHandler()
            self.SIZE_VERTEX_COORDINATES = self.vbo_handler.SIZE_OF_VERTEX_COORDINATES
        else:
            self.vbo_handler = VBOHandler(file_obj)
            self.SIZE_VERTEX_COORDINATES = 3
        
        # Reihenfolge wichtig fuer mapping
        self.cube_faces = [CUBE_LEFT,
                           CUBE_RIGHT,
                           CUBE_TOP,
                           CUBE_BOTTOM,
                           CUBE_FRONT,
                           CUBE_BACK                  
                           ]        
        
        # targets fuer Texturmapping spezifizieren vom Typ GLenum
        self.cube_targets = (GLenum * 6)(GL_TEXTURE_CUBE_MAP_POSITIVE_X,
                                 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
                                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
                                 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
                                 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
                                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
        
        # 6 Textur-IDs verwalten fuer 6 Wuerfelseiten
        self.texture_ids = glGenTextures(6)
        
        # Anzahl wieviel Koordinaten eine Textur besitzt (cubemap muss 3 haben!)
        self.__SIZE_TEXTURE_COORDINATES = 3
        
    def draw_skybox(self):
        glPushMatrix()
        #glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        #glLoadIdentity()
        glDisable(GL_TEXTURE_GEN_S)
        glDisable(GL_TEXTURE_GEN_T)
        glDisable(GL_TEXTURE_GEN_R)



        # habe Vertex-Koordinaten
        glEnableClientState(GL_VERTEX_ARRAY)
        # habe Textur-Koordinaten
        glEnableClientState(GL_TEXTURE_COORD_ARRAY)

        # vbo das cube koordinaten enthaelt benutzen
        self.vbo_handler.bind() 
    
        glVertexPointer(self.vbo_handler.SIZE_OF_VERTEX_COORDINATES, GL_FLOAT, self.vbo_handler.stride, self.vbo_handler.vertex_pointer)
        glTexCoordPointer(self.vbo_handler.SIZE_OF_VERTEX_COORDINATES, GL_FLOAT, self.vbo_handler.stride, self.vbo_handler.texture_pointer)
        # TODO: normalenpointer einfuegen und testen
    
        # Texturen zum zeichnen nochmal binden
        self.bind_textures()
        
        # Typ, Startindex, wieviele zu zeichnen Anzahl Vertices, Normals und Textures
        # FIXME: muss man length -1 angeben ?? 
        glDrawArrays(GL_QUADS, 0, self.vbo_handler.length)
    
        # unbind des vbo
        self.vbo_handler.unbind()
        glDisableClientState(GL_VERTEX_ARRAY)
        glDisableClientState(GL_TEXTURE_COORD_ARRAY)
        glEnable(GL_TEXTURE_GEN_S)
        glEnable(GL_TEXTURE_GEN_T)
        glEnable(GL_TEXTURE_GEN_R)
        glPopMatrix()
        
    def get_size_vertex_coordinates(self):
        return self.__SIZE_VERTEX_COORDINATES


    def get_size_texture_coordinates(self):
        return self.__SIZE_TEXTURE_COORDINATES


    def set_size_vertex_coordinates(self, value):
        self.__SIZE_VERTEX_COORDINATES = value


    def set_size_texture_coordinates(self, value):
        self.__SIZE_TEXTURE_COORDINATES = value


    def get_vbo_handler(self):
        return self.__vbo_handler


    def set_vbo_handler(self, value):
        self.__vbo_handler = value


    def get_texture_ids(self):
        return self.__texture_ids


    def set_texture_ids(self, value):
        self.__texture_ids = value

#        self.vertex_coordinates = self.get_vertex_coordinates()
        #self.vbo_handler_data_size = len(self.vertex_coordinates)
        
    def bind_textures(self):
        """Binden / aktivieren der Texturen zum Zeichen mit aktiviertem VBO"""
        # FIXME: noch nicht getestet
        for i in range(6):
            # binden
            glBindTexture(GL_TEXTURE_CUBE_MAP, self.texture_ids[0])

            # Zeichnen
            #glDrawArrays(GL_QUADS, 0, len(self.get_coordinates_list()))
    
        
    def init_skybox(self):
        glClearColor(1.,0.,0.,0.)
        #glCullFace(GL_BACK)
        #glFrontFace(GL_CCW)
        #glEnable(GL_CULL_FACE)
        #glEnable(GL_DEPTH_TEST)
    
        glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
        glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR)
        glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE)
    
        for i in range(6):
            glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_GENERATE_MIPMAP,GL_TRUE)
            data,w,h = self.load_image(self.cube_faces[i])
            glTexImage2D(self.cube_targets[i],0,GL_RGBA,512,512,0,GL_RGBA,GL_UNSIGNED_BYTE,data)
        glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_REFLECTION_MAP)
        glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_REFLECTION_MAP)
        glTexGeni(GL_R,GL_TEXTURE_GEN_MODE,GL_REFLECTION_MAP)
        
        glEnable(GL_TEXTURE_CUBE_MAP)
        glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL)

    
    def load_image(self,image):
        """Gibt liste von String zuruck, zur verarbeitung mit glTexImage2D"""
        # FIXME: methode mit array() aus Vorlesung anwenden (klappt nicht...)
        img = Image.open(image).rotate(180)
        w = img.size[0]
        h = img.size[1]
        d = img.tostring("raw","RGBX",0,-1)
        return d,w,h
    
    texture_ids = property(get_texture_ids, set_texture_ids, None, "texture_ids's docstring")
    SIZE_TEXTURE_COORDINATES = property(get_size_texture_coordinates, set_size_texture_coordinates, None, "SIZE_TEXTURE_COORDINATES's docstring")
    
    def __repr__(self):
        output = []
        output.append("Anzahl Texturkoordinaten (Skybox): %i" % self.SIZE_TEXTURE_COORDINATES)
        output.append("Texture IDs: %s" % self.texture_ids)
        
        return '\n'.join(output)
       
            
    def duplicate_vertices(self, lis=None):
        """Erwartet 1D Liste, Dupliziert jedes Zahlen-Triple und macht daraus eine Sublist
        [1, 2, 3, 4, 5, 6] -> [[1, 2, 3, 1, 2, 3], [4, 5, 6, 4, 5, 6]]"""
        if lis==None:
            lis = self.vertices
        ret = [2*lis[i:i+3] for i in range(0, len(lis), 3) ]
        return ret 
 
 
    def get_cube_map_vertices_and_textures(self, vertices=None):
        """Gibt liste fuer VBO nutzung einer CUBE_MAP formatiert zurueck"""        
        # GL_TEXTURE_CUBE_MAP braucht 3 Texturkoordinaten,
        # 3. koordinate ist x,y,z (die selbe wie Vertexkoordinate nehmen)
        if vertices==None:
            vertices = self.get_cube_map_vertices()
        cube_map_vertices_and_textures = self.duplicate_vertices(vertices)
        return  cube_map_vertices_and_textures
    
    
    
    vbo_handler = property(get_vbo_handler, set_vbo_handler, None, "vbo_handler's docstring")
    SIZE_VERTEX_COORDINATES = property(get_size_vertex_coordinates, set_size_vertex_coordinates, None, "SIZE_VERTEX_COORDINATES's docstring")
    SIZE_TEXTURE_COORDINATES = property(get_size_texture_coordinates, set_size_texture_coordinates, None, "SIZE_TEXTURE_COORDINATES's docstring")
           
if __name__ == '__main__':
    sb = Skybox()
    print sb
    
    
